///////////Ambient Light Effects by Adrian May & Shaun Mitchell
/////////// Depth of Field Effect by Adrian May



////////////////////////////// Variables //////////////////////////////////////////
float4x4 World;
float4x4 View;
float4x4 Projection;

float4x4 WorldInverseTranspose;

// Values read in by file
float3 DiffuseLightDirection;
float4 DiffuseLightColor;
float DiffuseIntensity;

float4 AmbientColor;
float AmbientIntensity;

float Shininess;
float4 SpecularColor;
float SpecularIntensity;

float3 ViewVector;

//DOF Values
texture RenderTargetTexture;
float Plane;
float4 vFocalPlane;
float HyperfocalDistance;

int Radius;
float centerTapWeight;
float2 texelSize;
//taps 5
float tapOffsets[4] = {-2, -1, 1, 2};
float4 tapWeights;

//////////////////////////// Structures ///////////////////////////////////////////

//-----------------------------------------------------------------------------
// Texture samplers
//-----------------------------------------------------------------------------
sampler RenderTargetSampler = 
sampler_state
{
    Texture = <RenderTargetTexture>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler2D textureSampler = sampler_state {
    MinFilter = Linear;
    MagFilter = Linear;
};

// Input to the vertex shader from application // with semantics
struct BasicInput
{
    float4 Position : POSITION0; // Vertex Position in object space
};
struct BasicOutput
{
	float4 Position : POSITION0; // Vertex Position in object space
};
struct VertexShaderInput
{
    float4 Position : POSITION0; // Vertex Position in object space
    float4 Normal : NORMAL0; // Normal vector
    float2 TextureCoordinate : TEXCOORD0; // Texture Coordinates
};

// Output to the pixel shader
struct VertexShaderOutput
{
    float4 Position : POSITION0; // Vertex Position in object space
    float4 Color : COLOR0; // Diffuse and specular color
    float3 Normal : TEXCOORD0; // Texture Coordinates
    float2 TextureCoordinate : TEXCOORD1; // Texture Coordinates
	float2 taps[4] : TEXCOORD2;
};
VertexShaderOutput DownSampleVS(VertexShaderInput input)
{
	VertexShaderOutput output;

	output.Position = input.Position;
	output.Color = float4(0,0,0,0);
	output.Normal = input.Normal;
	output.TextureCoordinate = input.TextureCoordinate;
	
	output.taps[0] = input.TextureCoordinate - texelSize / 4;
	output.taps[1] = input.TextureCoordinate + float2(-texelSize.x, texelSize.y) / 4;
	output.taps[2] = input.TextureCoordinate + float2(texelSize.x, -texelSize.y) / 4;
	output.taps[3] = input.TextureCoordinate + texelSize / 4;

	return output;
}
VertexShaderOutput VertexShaderFunction(VertexShaderInput input, uniform float2 Direction)
{
    VertexShaderOutput output;

	float3 vViewPosition;
    float3 vWorldNormal;
    float  BlurFactor;
	float4x4 WorldView;

	WorldView=mul(World,View);
	vViewPosition = mul(input.Position, WorldView);

	// multiply by world position, then view, then projection
    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
    
    // Take normal and transform to world space 
    float4 normal = mul(input.Normal, WorldInverseTranspose);
    
    // Get the dot product of normal and diffuse light direction vectors
    // normal.DiffuseLight = lightIntensity
    float lightIntensity = dot(normal, DiffuseLightDirection);
    
    // saturate is used to make sure a Color has values between 0 and 1 for each parameter
    output.Color = saturate(DiffuseLightColor * DiffuseIntensity * lightIntensity);

	// Output the normal to pixel shader
	output.Normal = normal;
	
	output.TextureCoordinate = input.TextureCoordinate;

	BlurFactor = dot(float4(vViewPosition, 1.0), vFocalPlane)*HyperfocalDistance;
	output.Color.a = abs(BlurFactor);//*BlurFactor;

	for(int i=0; i<4; i++)
	{

		output.taps[i] = input.TextureCoordinate + tapOffsets[i] * Direction * texelSize;
		

	}

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 // return type semantic
{
    // Get a copy of the normalized light direction and normal.
	float3 light = normalize(DiffuseLightDirection);
	float3 normal = normalize(input.Normal);
	
	// Calculate reflection vector
	float3 r = normalize(2* dot(light, normal) * normal - light);
	// View vector
	float3 v = normalize(mul(normalize(ViewVector), World));
	// Get dot product of 2 vectors
	float dotProduct = dot(r,v);
	
	// Calculate amount of specular // length is amount of diffuse light
	dotProduct = abs(dotProduct);
	float4 specular = SpecularIntensity * SpecularColor * max(pow(dotProduct, Shininess),0) * length(input.Color);

	
	float4 textureColor = tex2D(textureSampler, input.TextureCoordinate);
	textureColor.a = 1;

    return saturate(textureColor * (input.Color) + AmbientColor * AmbientIntensity + specular);
    
}
float4 RenderUnmodified( in float2 OriginalUV : TEXCOORD0 ) : COLOR 
{
    return tex2D(RenderTargetSampler, OriginalUV);

}
float4 RenderBlurFactor( in float2 OriginalUV : TEXCOORD0 ) : COLOR 
{
    float4 Original = tex2D(RenderTargetSampler, OriginalUV);
    return (1-Original.a); // Invert so the screen isn't pure white
}

float4 Blur( VertexShaderOutput input ) : COLOR
{
	float4x4 samples;
	float4 Original = tex2D(RenderTargetSampler, input.TextureCoordinate);
	float4 color = tex2D(RenderTargetSampler, input.TextureCoordinate) * centerTapWeight;
	float BlurFactor;

	for(int i=0; i<4; i++)
	{
		
		samples[i] = tex2D(RenderTargetSampler, input.taps[i]);
		if(samples[i].a<Original.a)
		{
			samples[i]=Original;
		}
	}
	BlurFactor = 1-Original.a;
	color += mul(tapWeights, samples);


	if(!BlurFactor==0)
	{
		//Original.r += 0.2;
		return Original;
	}
	return color;
}

float4 DownSamplePS(VertexShaderOutput input): COLOR
{
	float4x4 samples;
	for(int i=0;i<4;i++)
	{
		samples[i] = tex2D(RenderTargetSampler, input.taps[i]);
	}
	return mul(0.25f.xxxx, samples);
}




technique Basic
{
	pass Render
	{
	PixelShader = compile ps_2_0 RenderUnmodified();
	}

}
technique None
{
	pass Render
	{
		//VertexShader = compile vs_2_0 VSBASIC();
	  	 //PixelShader = compile ps_2_0 PSBASIC();
	}

}

technique Lighting
{
    pass P0
    {
       VertexShader = compile vs_2_0 VertexShaderFunction(float2(0,0));
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }

}



technique ShowBlur
{
	pass P0
	{
		PixelShader = compile ps_2_0 RenderBlurFactor();
	}
}

technique DOFwDown
{
	pass Downsample
	{
		VertexShader = compile vs_2_0 DownSampleVS();
		PixelShader = compile ps_2_0 DownSamplePS();
	}
	pass HBlur
	{
		VertexShader = compile vs_2_0 VertexShaderFunction(float2(1,0));
		PixelShader = compile ps_2_0 Blur();
	}

	pass VBlur
	{
		VertexShader = compile vs_2_0 VertexShaderFunction(float2(0,1));
		PixelShader = compile ps_2_0 Blur();
	}

}

technique DOF
{
	pass HBlur
	{
		VertexShader = compile vs_2_0 VertexShaderFunction(float2(1,0));
		PixelShader = compile ps_2_0 Blur();
	}

	pass VBlur
	{
		VertexShader = compile vs_2_0 VertexShaderFunction(float2(0,1));
		PixelShader = compile ps_2_0 Blur();
	}
}